import type { AxiosRequestConfig, AxiosInstance } from 'axios'
import axios from 'axios'
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import { Session } from '@/utils/storage'
import { TokenKey } from '@/utils'
import { clone } from 'xe-utils'
import { themeConfig, token } from '@/storage'
import { getCryptoString, headerSign } from '@/utils/crypto'

// 默认缓存请求时间
export const defaultCacheAge = 60 * 60 * 1000 // 请求缓存一个小时
// 全局缓存数据
const cache: TypedAny = {}

/**
 * 生成key
 * @param config
 */
const generateCacheKey = (config: AxiosRequestConfig) => {
  const { url, data, params } = config
  let param = {}
  if (params) {
    param = params
  } else if (data) {
    param = JSON.parse(data)
  }
  // 查询参数排序
  const sortedParams = sortParams(param)
  // 查询参数序列化
  const serializedParams = serializeParams(sortedParams)
  return `${url}${serializedParams}`
}

/**
 * 排序参数
 * @param params
 */
const sortParams = (params: TypedAny) => {
  return Object.keys(params)
    .sort()
    .reduce((sorted: TypedAny, key) => {
      sorted[key] = params[key]
      return sorted
    }, {})
}

/**
 * 序列化参数
 * @param params
 */
const serializeParams = (params: TypedAny) => {
  return Object.entries(params)
    .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
    .join('&')
}

/**
 * 自定义缓存
 * @param config
 */
const cacheAdapter = async (config: AxiosRequestConfig) => {
  const cacheAge = config.cacheAge
  if (themeConfig.value.isRequestCache && cacheAge) {
    // console.log(`已缓存 ${Object.keys(cache).length} 个请求。`)
    const cacheKey = generateCacheKey(config)
    const cacheRes = cache[cacheKey]
    const currentTime = Date.now()
    const diff = currentTime - (cacheRes ? cacheRes.time : 0)
    if (cacheRes && diff < cacheAge) {
      return Promise.resolve(clone(cacheRes.res, true))
    } else {
      delete config.adapter
      return axios(config).then((res) => {
        if (res.data && res.data.data) {
          cache[cacheKey] = {
            res: clone(res, true),
            time: Date.now()
          }
        }
        return res
      })
    }
  } else {
    delete config.adapter
    return axios(config)
  }
}

// 配置新建一个 axios 实例
const service: AxiosInstance = axios.create({
  adapter: cacheAdapter,
  // baseURL: import.meta.env.VITE_API_URL,
  baseURL: '',
  timeout: 50000
})

// 添加请求拦截器
service.interceptors.request.use(
  (config) => {
    // 在发送请求之前做些什么 token
    if (token.value) config.headers![TokenKey] = `Bearer ${token.value}`

    config.headers[headerSign] = getCryptoString()

    return config
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error)
  }
)

// 添加响应拦截器
service.interceptors.response.use(
  async (response) => {
    // 对响应数据做点什么
    const res = response.data
    // const dd = await cache.store.length()
    // console.log('dd', dd)
    if (res.notice) {
      ElNotification({
        title: '提示信息',
        message: res.notice,
        type: 'info',
        duration: 0
      })
    }

    if (res.code && res.code !== 0) {
      // `token` 过期或者账号已在别处登录
      if (res.code === 401 || res.code === 4001) {
        Session.clear() // 清除浏览器全部临时缓存
        window.location.href = '/' // 去登录页
        ElMessageBox.alert('你已被登出，请重新登录', '提示', {})
          .then(() => {})
          .catch(() => {})
      } else {
        ElMessage.warning(res.msg || '服务器错误')
      }
      return Promise.reject(service.interceptors.response)
    } else {
      return res
    }
  },
  (error) => {
    console.log('error', error)
    // 对响应错误做点什么
    if (error.response.status === 401) {
      Session.clear() // 清除浏览器全部临时缓存
      window.location.href = '/' // 去登录页
    } else if (error.message.indexOf('timeout') != -1) {
      ElMessage.error('网络超时')
    } else if (error.message == 'Network Error') {
      ElMessage.error('网络连接错误')
    } else {
      if (error.response.data) ElMessage.error(error.response.statusText)
      else ElMessage.error('接口路径找不到')
    }
    return Promise.reject(error)
  }
)

// 导出 axios 实例
export default service
